// es6 --   mixin
// 作者 王欢
// 开始日期 2019-12-20
// 解决小程序  实例 组件 混入问题
// 基本思路与用法  参考vue
/* 
  修改 wanghuan
  1. 修改合并机制，改为深度合并
  2. 在全局混入 computed 计算机制
  date:  2020/4/48
  整合 computed 到全局 mixins函数
  2021/04/09 更新: 
  3.  深度混入  
  描述： 完成 page A混入 B， B又混入 c ... 等这种多层级混入的机制
  2021/04/24 更新: 
  4.  组件混入功能开启  同时组件混入  computed 计算属性  方法同Page构造器一样   
  2021/09/17
  5.混入页面或者组件实例-方法  两者互相兼容  ###  定义方法( 页面方法定义在根对象上,组件定义在methods里 )

  */
const { $isType, $merge, $to } = require("./common");
const { $model } = require("./main");
const { $computed, _computedKeys } = require('./computed');
const { $url, $back } = require('./router');
const { $get, $post, $put, $delete } = require('./http');
const { $static } = require('./config');
const { $log, $fail } = require('./layer');
/* -------------------------------------  Page mixins ----------------------------- */
const lifecycle_Page = ['onLoad', 'onReady', 'onShow', 'onHide', 'onUnload', 'onPullDownRefresh', 'onReachBottom', 'onShareAppMessage', 'onPageScroll'];
const globalMixin_Page = {
  // 在全局混入中加入 onLoad生命周期函数  初始化  computed
  data: {
    $static
  }
  , $url
  , $back
  , $get
  , $post
  , $put
  , $delete
  , $to
  , $log
  , $fail
  , $model
  , onLoad() {
    $computed.call(this);
  }

};

const nativePage = Page;
Page = function (config) {
  let mixinsDeep = [];
  // 深入收集子 mixins 的函数
  function getChildrenMixs(mixConfig) {
    const c_mixins = mixConfig.mixins;
    if ($isType(c_mixins, 'Array') && c_mixins.length != 0) {
      mixinsDeep.push(...c_mixins);
      c_mixins.forEach(c_mixs_config => {
        getChildrenMixs(c_mixs_config);
      });
    }
  }
  getChildrenMixs(config);
  //加入全局mixin
  if (globalMixin_Page) {
    mixinsDeep.unshift(globalMixin_Page);
  }
  _extend(mixinsDeep, config);
  nativePage(config);
}


/* ---------------- Components mixins ------------------------------ */

const lifecycle_Component = ["created", "attached", "ready", "moved", "detached", "error"];
const globalMixin_Component = {
  data: {
    $static
  }
  , methods: {
    $url
    , $back
    , $get
    , $post
    , $put
    , $delete
    , $to
    , $log
    , $fail
    , $model
  }
  , attached() {
    $computed.call(this, false);
  }
};
/* 
  组件全局  mixins computed
*/
const nativeComponent = Component;
Component = function (config) {
  let mixinsDeep = [];
  // 深入收集子 mixins 的函数
  function getChildrenMixs(mixConfig) {
    const c_mixins = mixConfig.mixins;
    if ($isType(c_mixins, 'Array') && c_mixins.length != 0) {
      mixinsDeep.push(...c_mixins);
      c_mixins.forEach(c_mixs_config => {
        getChildrenMixs(c_mixs_config);
      });
    }
  }
  getChildrenMixs(config);
  //加入全局mixin
  if (globalMixin_Component) {
    mixinsDeep.unshift(globalMixin_Component);
  }
  _extend(mixinsDeep, config, false);
  const computedData = config[_computedKeys._Page];
  if (computedData && $isType(computedData, "Object")) {
    const { data } = config;
    data[_computedKeys._Component] = computedData;
  }
  nativeComponent(config);
}

/* 
 合并函数  
  对特殊属性  data computed 进行深度合并  
  对生命周期函数 onload onReady  合并在当前路由生命周期内
  对自定义方法  进行浅合并
  _extend(mixins:Object,config:Object);
*/
//页面 组件  共有合并关键字
const public_mergeKeys = [
  "data"
  , _computedKeys._Page
];
//组件合并关键字
const component_mergeKeys = [
  "behaviors"
  , "properties"
  , "lifetimes"
  , "methods"
  , "options"
];
function _extend(mixins, config, isPage = true) {
  let _lifecycle;
  if (isPage) {
    _lifecycle = lifecycle_Page;
  } else {
    _lifecycle = lifecycle_Component;
  }
  // 针对 对象 或者 数组的高阶合并
  function _mixins_merge(mixin, key) {
    if (config[key] === undefined) {
      config[key] = mixin[key];
    } else {
      $merge(config[key], mixin[key]);
    }
  }
  mixins.forEach(mixin => {
    if ($isType(mixin, 'Object')) {
      Object.keys(mixin).forEach(key => {
        //合并 页面或者 组件 data, computed
        if (public_mergeKeys.includes(key)) {
          _mixins_merge(mixin, key);
          //合并 页面或者 组件 生命周期
        } else if (_lifecycle.includes(key)) {
          let nativeLifecycle = config[key];
          if (nativeLifecycle) {
            config[key] = function () {
              let arg = Array.prototype.slice.call(arguments);
              mixin[key].apply(this, arg);
              return nativeLifecycle && nativeLifecycle.apply(this, arg);
            }
          } else {
            config[key] = mixin[key];
          }
          /* 页面 或者 组件 方法混入 */
        } else {
          // 页面方法混入
          if (isPage) {
            //排除组件关键字于生命周期
            if (!lifecycle_Component.includes(key)) {
              if (config[key] === undefined) {
                if (key !== "methods") {
                  config[key] = mixin[key];
                } else {
                  //对组件实例methods进行方法合并
                  if( $isType(mixin[key], "Object") ){
                    $merge( config , mixin[key] );
                  }
                }
              }
            }

          } else {
            // 组件方法混入
            if (component_mergeKeys.includes(key)) {
              _mixins_merge(mixin, key);
            } else {
              // 排除页面关键字与生命周期
              if (!lifecycle_Page.includes(key)) {
                //判断组件 methods是否定义
                if (!("methods" in config)) {
                  config.methods = {};
                }
                // 组件methods定义且为对象
                // 合并方法
                const { methods: cpt_methods } = config;
                if (cpt_methods
                  && $isType(cpt_methods, "Object")
                  && cpt_methods[key] === undefined
                ) {
                  cpt_methods[key] = mixin[key];
                }
              }
            }
          }
        }
      })
    }
  })
}

